	AREA |.text|, CODE, READONLY, ALIGN=2
	THUMB
	REQUIRE8
	PRESERVE8

PCM RN r0
VB1 RN r1
COEF RN r2

VLO RN r0
VHI RN r3

SUM1LL RN r4
SUM1LH RN r5
SUM2LL RN r6
SUM2LH RN r7
SUM1RL RN r8
SUM1RH RN r9
SUM2RL RN r10
SUM2RH RN r11

CF1 RN r12
CF2 RN r14

SIGN RN r12
MAXPOS RN r14

I RN r12

	GBLA RNDVAL
RNDVAL SETA (1 << ((32 - 12) + (6 - 1)))

	; C64TOS - clip 64-bit accumulator to short (no rounding)
	; xl, xh = value (lo 32, hi 32)
	; input assumed to have 6 fraction bits
	; sign = temp variable to use for sign
	; maxPos = 0x00007fff (takes 2 instr. to generate - calculating
	; once and using repeatedly saves if you do several CTOS in a row) */
	MACRO
		C64TOS $xl, $xh, $sign, $maxPos

	mov $xl, $xl, lsr #(20+6)
	orr $xl, $xl, $xh, lsl #(12-6)
	mov $sign, $xl, ASR #31
	cmp $sign, $xl, ASR #15
	it ne
	eorne $xl, $sign, $maxPos
	MEND ; C64TOS

	; MC0S - process 2 taps, 1 sample per channel (sample 0) */
	; x = vb1 offset */
	MACRO
		MC0S $x

	ldr CF1, [COEF], #4
	ldr CF2, [COEF], #4
	ldr VLO, [VB1, #(4*($x))]
	ldr VHI, [VB1, #(4*(23 - $x))]

	smlal SUM1LL, SUM1LH, VLO, CF1
	ldr VLO, [VB1, #(4*(32 + $x))]
	rsb CF2, CF2, #0
	smlal SUM1LL, SUM1LH, VHI, CF2
	ldr VHI, [VB1, #(4*(32 + 23 - $x))]

	smlal SUM1RL, SUM1RH, VLO, CF1
	smlal SUM1RL, SUM1RH, VHI, CF2

	MEND ; MCOS

	; MC1S - process 2 taps, 1 sample per channel (sample 16)
	; x = vb1 offset
	MACRO
		MC1S $x

	ldr CF1, [COEF], #4
	ldr VLO, [VB1, #(4*($x))]
	ldr VHI, [VB1, #(4*(32 + $x))]
	smlal SUM1LL, SUM1LH, VLO, CF1
	smlal SUM1RL, SUM1RH, VHI, CF1

	MEND ; MC1S

	; MC2S - process 2 taps, 2 samples per channel
	; x = vb1 offset
	MACRO
		MC2S $x

	; load data as far as possible in advance of using it
	ldr CF1, [COEF], #4
	ldr CF2, [COEF], #4
	ldr VLO, [VB1, #(4*($x))]
	ldr VHI, [VB1, #(4*(23 - $x))]

	smlal SUM1LL, SUM1LH, VLO, CF1
	smlal SUM2LL, SUM2LH, VLO, CF2
	rsb CF2, CF2, #0
	smlal SUM2LL, SUM2LH, VHI, CF1
	smlal SUM1LL, SUM1LH, VHI, CF2

	ldr VHI, [VB1, #(4*(32 + 23 - $x))]
	ldr VLO, [VB1, #(4*(32 + $x))]

	smlal SUM1RL, SUM1RH, VHI, CF2
	smlal SUM2RL, SUM2RH, VHI, CF1
	rsb CF2, CF2, #0
	smlal SUM1RL, SUM1RH, VLO, CF1
	smlal SUM2RL, SUM2RH, VLO, CF2

	MEND ; MC2S
		
		
; void PolyphaseStereo(short *pcm, int *vbuf, const int *coefBase)
xmp3_PolyphaseStereo PROC
	EXPORT xmp3_PolyphaseStereo

	stmfd sp!, {r4-r11, r14}

		; clear out stack space for 2 local variables (4 bytes each)
	sub sp, sp, #8
	str PCM , [sp, #4] ; sp[1] = pcm pointer

	; special case, output sample 0
	mov SUM1LL, #RNDVAL ; load rndVal (low 32)
	mov SUM1RL, #RNDVAL ; load rndVal (low 32)
	mov SUM1LH, #0
	mov SUM1RH, #0

	MC0S 0
	MC0S 1
	MC0S 2
	MC0S 3
	MC0S 4
	MC0S 5
	MC0S 6
	MC0S 7

	ldr PCM, [sp, #4] ; load pcm pointer
	mov MAXPOS, #0x7f00
	orr MAXPOS, MAXPOS, #0xff

	C64TOS SUM1LL, SUM1LH, SIGN, MAXPOS
	C64TOS SUM1RL, SUM1RH, SIGN, MAXPOS

	strh SUM1LL, [PCM, #(2*0)]
	strh SUM1RL, [PCM, #(2*1)]

	; special case, output sample 16
	add COEF, COEF, #(4*(256-16)) ; coef = coefBase + 256 (was coefBase + 16 after MC0S block)
	add VB1, VB1, #(4*1024) ; vb1 = vbuf + 64*16

	mov SUM1LL, #RNDVAL ; load rndVal (low 32)
	mov SUM1RL, #RNDVAL ; load rndVal (low 32)
	mov SUM1LH, #0
	mov SUM1RH, #0

	MC1S 0
	MC1S 1
	MC1S 2
	MC1S 3
	MC1S 4
	MC1S 5
	MC1S 6
	MC1S 7

	ldr PCM, [sp, #4] ; load pcm pointer
	mov MAXPOS, #0x7f00
	orr MAXPOS, MAXPOS, #0xff

	C64TOS SUM1LL, SUM1LH, SIGN, MAXPOS
	C64TOS SUM1RL, SUM1RH, SIGN, MAXPOS

	strh SUM1LL, [PCM, #(2*(2*16+0))]
	strh SUM1RL, [PCM, #(2*(2*16+1))]

	; main convolution loop: sum1L = samples 1, 2, 3, ... 15 sum2L = samples 31, 30, ... 17
	sub COEF, COEF, #(4*(264-16)) ; coef = coefBase + 16 (was coefBase + 264 after MC1S block)
	sub VB1, VB1, #(4*(1024-64)) ; vb1 = vbuf + 64 (was vbuf + 64*16 after MC1S block)
	mov I, #15 ; loop counter, count down
	add PCM, PCM, #(2*2) ; pcm+=2

LoopPS
	str I, [sp, #0] ; sp[0] = i (loop counter)
	str PCM, [sp, #4] ; sp[1] = pcm (pointer to pcm buffer)

	mov SUM1LL, #RNDVAL ; load rndVal (low 32)
	mov SUM1RL, #RNDVAL ; load rndVal (low 32)
	mov SUM2LL, #RNDVAL ; load rndVal (low 32)
	mov SUM2RL, #RNDVAL ; load rndVal (low 32)

	mov SUM1LH, #0
	mov SUM1RH, #0
	mov SUM2LH, #0
	mov SUM2RH, #0

	MC2S 0
	MC2S 1
	MC2S 2
	MC2S 3
	MC2S 4
	MC2S 5
	MC2S 6
	MC2S 7

	add VB1, VB1, #(4*64) ; vb1 += 64

	ldr PCM, [sp, #4] ; load pcm pointer
	mov MAXPOS, #0x7f00
	orr MAXPOS, MAXPOS, #0xff

	C64TOS SUM1LL, SUM1LH, SIGN, MAXPOS
	C64TOS SUM1RL, SUM1RH, SIGN, MAXPOS
	C64TOS SUM2LL, SUM2LH, SIGN, MAXPOS
	C64TOS SUM2RL, SUM2RH, SIGN, MAXPOS

	ldr I, [sp, #0] ; load loop counter
	add CF2, PCM, I, lsl #3 ; CF2 = PCM + 4*i (short offset)
	strh SUM2LL, [CF2], #2 ; *(pcm + 2*2*i + 0)
	strh SUM2RL, [CF2], #2 ; *(pcm + 2*2*i + 1)

	strh SUM1LL, [PCM], #2 ; *(pcm + 0)
	strh SUM1RL, [PCM], #2 ; *(pcm + 1)

	subs I, I, #1
	bne LoopPS

	; restore stack pointer
	add sp, sp, #8

	ldmfd sp!, {r4-r11, pc}

	ENDP

; MONO PROCESSING

	; MC0M - process 2 taps, 1 sample (sample 0)
	; x = vb1 offset
	MACRO
		MC0M $x

	ldr CF1, [COEF], #4
	ldr CF2, [COEF], #4
	ldr VLO, [VB1, #(4*($x))]
	ldr VHI, [VB1, #(4*(23 - $x))]

	rsb CF2, CF2, #0
	smlal SUM1LL, SUM1LH, VLO, CF1
	smlal SUM1LL, SUM1LH, VHI, CF2

	MEND ; MC0M

		; MC1M - process 2 taps, 1 sample (sample 16)
	; x = vb1 offset
	MACRO
		MC1M $x

	ldr CF1, [COEF], #4
	ldr VLO, [VB1, #(4*($x))]
	smlal SUM1LL, SUM1LH, VLO, CF1

	MEND ; MC1M

	; MC2M - process 2 taps, 2 samples
	; x = vb1 offset
	MACRO
		MC2M $x

	; load data as far as possible in advance of using it
	ldr CF1, [COEF], #4
	ldr CF2, [COEF], #4
	ldr VLO, [VB1, #(4*($x))]
	ldr VHI, [VB1, #(4*(23 - $x))]

	smlal SUM1LL, SUM1LH, VLO, CF1
	smlal SUM2LL, SUM2LH, VLO, CF2
	rsb CF2, CF2, #0
	smlal SUM1LL, SUM1LH, VHI, CF2
	smlal SUM2LL, SUM2LH, VHI, CF1

	MEND ; MC2M

; void PolyphaseMono(short *pcm, int *vbuf, const int *coefBase)

xmp3_PolyphaseMono PROC
		EXPORT xmp3_PolyphaseMono

	stmfd sp!, {r4-r11, r14}

	; clear out stack space for 4 local variables (4 bytes each)
	sub sp, sp, #8
	str PCM, [sp, #4] ; sp[1] = pcm pointer

	; special case, output sample 0
	mov SUM1LL, #RNDVAL ; load rndVal (low 32)
	mov SUM1LH, #0

	MC0M 0
	MC0M 1
	MC0M 2
	MC0M 3
	MC0M 4
	MC0M 5
	MC0M 6
	MC0M 7

	ldr PCM, [sp, #4] ; load pcm pointer
	mov MAXPOS, #0x7f00
	orr MAXPOS, MAXPOS, #0xff

	C64TOS SUM1LL, SUM1LH, SIGN, MAXPOS
	strh SUM1LL, [PCM, #(2*0)]

	; special case, output sample 16
	add COEF, COEF, #(4*(256-16)) ; coef = coefBase + 256 (was coefBase + 16 after MC0M block)
	add VB1, VB1, #(4*1024) ; vb1 = vbuf + 64*16

	mov SUM1LL, #RNDVAL ; load rndVal (low 32)
	mov SUM1LH, #0

	MC1M 0
	MC1M 1
	MC1M 2
	MC1M 3
	MC1M 4
	MC1M 5
	MC1M 6
	MC1M 7

	ldr PCM, [sp, #4] ; load pcm pointer
	mov MAXPOS, #0x7f00
	orr MAXPOS, MAXPOS, #0xff

	C64TOS SUM1LL, SUM1LH, SIGN, MAXPOS

	strh SUM1LL, [PCM, #(2*16)]

	; main convolution loop: sum1L = samples 1, 2, 3, ... 15 sum2L = samples 31, 30, ... 17
	sub COEF, COEF, #(4*(264-16)) ; coef = coefBase + 16 (was coefBase + 264 after MC1M block)
	sub VB1, VB1, #(4*(1024-64)) ; vb1 = vbuf + 64 (was vbuf + 64*16 after MC1M block)
	mov I, #15 ; loop counter, count down
	add PCM, PCM, #(2) ; pcm++

LoopPM
	str I, [sp, #0] ; sp[0] = i (loop counter)
	str PCM, [sp, #4] ; sp[1] = pcm (pointer to pcm buffer)

	mov SUM1LL, #RNDVAL ; load rndVal (low 32)
	mov SUM2LL, #RNDVAL ; load rndVal (low 32)
	mov SUM1LH, #0
	mov SUM2LH, #0

	MC2M 0
	MC2M 1
	MC2M 2
	MC2M 3
	MC2M 4
	MC2M 5
	MC2M 6
	MC2M 7

	add VB1, VB1, #(4*64) ; vb1 += 64

	ldr PCM, [sp, #4] ; load pcm pointer
	mov MAXPOS, #0x7f00
	orr MAXPOS, MAXPOS, #0xff

	C64TOS SUM1LL, SUM1LH, SIGN, MAXPOS
	C64TOS SUM2LL, SUM2LH, SIGN, MAXPOS

	ldr I, [sp, #0] ; load loop counter*/
	add CF2, PCM, I, lsl #2 ; CF2 = PCM + 2*i (short offset)*/
	strh SUM2LL, [CF2], #2 ; (pcm + 2*i + 0)
	strh SUM1LL, [PCM], #2 ; (pcm + 0) ; pcm++

	subs I, I, #1
	bne LoopPM

	; restore stack pointer
	add sp, sp, #8

	ldmfd sp!, {r4-r11, pc}
	ENDP

	END